Thread: Program crash[C/SDL/Win32]

  1. #1
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288

    Program crash[C/SDL/Win32]

    Note for the mods : I was confused to where I should put this, but I finally decided more people would be familiar with C/SDL/Win32 libraries here. I assumed you could move it somewhere if it was in the wrong spot.

    My program worked when I kept it in simple console graphics, but for some reason it crashes with SDL added to it. The part that confuses me is when I tried to see if a specific statement caused the crash, I couldn't. It only seems to crash after the wait functions start to execute. With no errors or warnings, and with my debugger being caught by SIGTRAP, and with none of my error-handling code running, I can't tell what the problem is. The code is rather long, but I'll post it anyways. If you want me to divide it into smaller sections, I can, but I can't be sure where the error is.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    #include <process.h>
    #define WIN_32_LEAN_AND_MEAN
    #include <windows.h>
    #include <strsafe.h>
    
    
    #include <SDL/SDL.h>
    
    
    #define MAX_RIGHT 79
    #define MAX_DOWN 24
    
    
    #define MAX_THREADS 7
    
    
    /* Key-input macro and usage credit goes to : http://cboard.cprogramming.com/c-programming/157472-c-pong-program-need-help-smoothing-animations.html */
    
    
    #define VKEY_IS_PRESSED(vk)	( GetAsyncKeyState(vk) & 0x8000 )
    
    
    enum v_key
    {
        up_arrow = VK_UP,
        down_arrow = VK_DOWN,
        right_arrow = VK_RIGHT,
        left_arrow = VK_LEFT,
        clearscreen = VK_BACK,
        escape = VK_ESCAPE
    };
    
    
    typedef struct shared_game_data
    {
        SDL_Surface * screen;
        SDL_Surface * bmp;
        SDL_Rect dstrect;
    
    
    
    
    } shared_game_data;
    
    
    void * data = NULL;
    HANDLE h_threads[MAX_THREADS] = {0};
    
    
    HANDLE up_arrow_event = 0;
    HANDLE down_arrow_event = 0;
    HANDLE right_arrow_event = 0;
    HANDLE left_arrow_event = 0;
    HANDLE clear_screen_event = 0;
    HANDLE escape_event = 0;
    HANDLE debounce_event = 0;
    
    
    CRITICAL_SECTION critical_section;
    
    
    BOOL is_debounce = FALSE;
    
    
    /* Credit to the board : http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1044844545&id=1043284392 */
    
    
    void gotoxy(int x, int y)
    {
      COORD coord;
      coord.X = x;
      coord.Y = y;
      SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
    }
    
    
    /* Credit to Microsoft : http://msdn.microsoft.com/en-us/library/windows/desktop/ms682022(v=vs.85).aspx */
    
    
    void cls( HANDLE hConsole )
    {
       COORD coordScreen = { 0, 0 };
       DWORD cCharsWritten;
       CONSOLE_SCREEN_BUFFER_INFO csbi;
       DWORD dwConSize;
    
    
       if( !GetConsoleScreenBufferInfo( hConsole, &csbi ))
          return;
    
    
       dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
    
    
       if( !FillConsoleOutputCharacter( hConsole, (TCHAR) ' ', dwConSize,coordScreen, &cCharsWritten ))
          return;
    
    
       if( !GetConsoleScreenBufferInfo( hConsole, &csbi ))
          return;
    
    
       if( !FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten ))
          return;
    
    
       SetConsoleCursorPosition( hConsole, coordScreen );
    }
    
    
    /* Credit to Microsoft : http://msdn.microsoft.com/en-us/library/windows/apps/ms680582(v=vs.85).aspx */
    
    
    void ErrorExit(LPTSTR lpszFunction)
    {
        LPVOID lp_msg_buf;
        LPVOID lp_display_buf;
        DWORD dw = GetLastError();
    
    
        FormatMessage
        (
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lp_msg_buf,
        0,
        NULL
        );
    
    
        lp_display_buf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lp_msg_buf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
    
    
        StringCchPrintf((LPTSTR)lp_display_buf, LocalSize(lp_display_buf) / sizeof(TCHAR), TEXT("%s failed with error %d: %s"), lpszFunction, dw, lp_msg_buf);
        MessageBox(NULL, (LPCTSTR)lp_display_buf, TEXT("Error"), MB_OK);
    
    
        LocalFree(lp_msg_buf);
        LocalFree(lp_display_buf);
        ExitProcess(dw);
    }
    
    
    void SDL_errorexit( const char * error_message, const char * caption  )
    {
            char buffer[BUFSIZ];
            StringCbPrintfA(buffer, BUFSIZ, "%s : %s", error_message, SDL_GetError());
            MessageBox( NULL, buffer, caption, MB_OK | MB_ICONEXCLAMATION );
    
    
            exit(1);
    }
    
    
    void close_events( )
    {
        CloseHandle(up_arrow_event);
        CloseHandle(down_arrow_event);
        CloseHandle(right_arrow_event);
        CloseHandle(left_arrow_event);
        CloseHandle(escape_event);
        CloseHandle(clear_screen_event);
        CloseHandle(debounce_event);
    
    
        return;
    }
    
    
    void close_threads( )
    {
        unsigned index;
    
    
        for (index = 0; index < MAX_THREADS; index++)
            CloseHandle(h_threads[index]);
    
    
        return;
    }
    
    
    unsigned __stdcall debounce_events( void * m_sleep )
    {
        const DWORD msleep = *(DWORD *)m_sleep;
        DWORD return_value = 0;
        HANDLE objects[2] = {debounce_event, escape_event};
    
    
        for ( ; ; )
        {
    
    
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
    
    
                    is_debounce = TRUE;
                    Sleep(msleep);
                    is_debounce = FALSE;
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    unsigned __stdcall event_loop( void * m_sleep )
    {
        const DWORD msleep = *(DWORD *)m_sleep;
    
    
        for (;;)
    	{
    	    if (!is_debounce)
    	    {
    
    
                if ( VKEY_IS_PRESSED(escape) )
                {
                    if ( !SetEvent(escape_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-Escape"));
                    }
    
    
                    return 0;
                }
    
    
                if ( VKEY_IS_PRESSED(up_arrow) )
                {
                    if ( !SetEvent(up_arrow_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-UpArrow"));
                    }
    
    
                    if ( !SetEvent(debounce_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("DebounceEvent-UpArrow"));
                    }
                }
    
    
                if ( VKEY_IS_PRESSED(down_arrow) )
                {
                    if ( !SetEvent(down_arrow_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-DownArrow"));
                    }
    
    
                    if ( !SetEvent(debounce_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("DebounceEvent-UpArrow"));
                    }
                }
    
    
                if ( VKEY_IS_PRESSED(right_arrow) )
                {
    
    
                    if ( !SetEvent(right_arrow_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-RightArrow"));
                    }
    
    
                    if ( !SetEvent(debounce_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("DebounceEvent-UpArrow"));
                    }
                }
    
    
                if ( VKEY_IS_PRESSED(left_arrow) )
                {
                    if ( !SetEvent(left_arrow_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-LeftArrow"));
                    }
    
    
                    if ( !SetEvent(debounce_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("DebounceEvent-UpArrow"));
                    }
                }
    
    
                if ( VKEY_IS_PRESSED(clearscreen) )
                {
                    if ( !SetEvent(clear_screen_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-ClearScreen"));
                    }
                }
    
    
            }
    
    
    		Sleep(msleep);
    	}
    
    
    	return 1;
    }
    
    
    unsigned __stdcall left_arrow_handler( void * parameter )
    {
        DWORD return_value = 0;
        HANDLE objects[2] = {left_arrow_event, escape_event};
        shared_game_data * my_data = (shared_game_data *)parameter;
    
    
        for ( ; ; )
        {
    
    
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
                    EnterCriticalSection(&critical_section);
    
    
                    if ( (my_data->dstrect.x - 1) > -1 )
                    {
                        SDL_FillRect(my_data->screen, NULL, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        --my_data->dstrect.x;
                        SDL_FillRect(my_data->screen, 0, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        SDL_BlitSurface(my_data->bmp, 0, my_data->screen, &my_data->dstrect);
                        SDL_Flip(my_data->screen);
                    }
    
    
                    LeaveCriticalSection(&critical_section);
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    unsigned __stdcall right_arrow_handler( void * parameter )
    {
        DWORD return_value = 0;
        HANDLE objects[2] = {right_arrow_event, escape_event};
        shared_game_data * my_data = (shared_game_data *)parameter;
    
    
        for ( ; ; )
        {
    
    
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
                    EnterCriticalSection(&critical_section);
    
    
                    if ( (my_data->dstrect.x + 1) > -1 && (my_data->dstrect.x + 1) <= MAX_RIGHT )
                    {
                        SDL_FillRect(my_data->screen, NULL, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        ++my_data->dstrect.x;
                        SDL_FillRect(my_data->screen, 0, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        SDL_BlitSurface(my_data->bmp, 0, my_data->screen, &my_data->dstrect);
                        SDL_Flip(my_data->screen);
                    }
    
    
                    LeaveCriticalSection(&critical_section);
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    unsigned __stdcall down_arrow_handler( void * parameter )
    {
        DWORD return_value = 0;
        HANDLE objects[2] = {down_arrow_event, escape_event};
        shared_game_data * my_data = (shared_game_data *)parameter;
    
    
        for ( ; ; )
        {
    
    
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
                    EnterCriticalSection(&critical_section);
    
    
                    if ( (my_data->dstrect.y + 1) > -1 && (my_data->dstrect.y + 1) <= MAX_DOWN )
                    {
                        SDL_FillRect(my_data->screen, NULL, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        ++my_data->dstrect.y;
                        SDL_FillRect(my_data->screen, 0, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        SDL_BlitSurface(my_data->bmp, 0, my_data->screen, &my_data->dstrect);
                        SDL_Flip(my_data->screen);
                    }
    
    
                    LeaveCriticalSection(&critical_section);
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    unsigned __stdcall up_arrow_handler( void * parameter )
    {
        DWORD return_value = 0;
        HANDLE objects[2] = {up_arrow_event, escape_event};
        shared_game_data * my_data = (shared_game_data *)parameter;
    
    
        for ( ; ; )
        {
    
    
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
                    EnterCriticalSection(&critical_section);
    
    
                    if ( (my_data->dstrect.y - 1) > -1 )
                    {
                        SDL_FillRect(my_data->screen, NULL, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        --my_data->dstrect.x;
                        SDL_FillRect(my_data->screen, 0, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        SDL_BlitSurface(my_data->bmp, 0, my_data->screen, &my_data->dstrect);
                        SDL_Flip(my_data->screen);
                    }
    
    
                    LeaveCriticalSection(&critical_section);
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    unsigned __stdcall clear_screen_handler( void * parameter )
    {
        DWORD return_value = 0;
        HANDLE objects[2] = {clear_screen_event, escape_event};
        shared_game_data * my_data = (shared_game_data *)parameter;
    
    
        for ( ; ; )
        {
    
    
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
                    EnterCriticalSection(&critical_section);
    
    
                    SDL_FillRect(my_data->screen, NULL, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                    my_data->dstrect.x = 0;
                    my_data->dstrect.y = 0;
                    SDL_FillRect(my_data->screen, 0, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                    SDL_BlitSurface(my_data->bmp, 0, my_data->screen, &my_data->dstrect);
                    SDL_Flip(my_data->screen);
    
    
                    LeaveCriticalSection(&critical_section);
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    void init_events ( )
    {
        /* Create our keyboard events */
    
    
        up_arrow_event = CreateEvent( NULL, TRUE, FALSE, TEXT("UpArrowEvent") );
    
    
        if (!up_arrow_event)
            ErrorExit(TEXT("CreateEvent 1"));
    
    
        down_arrow_event = CreateEvent( NULL, TRUE, FALSE, TEXT("DownArrowEvent") );
    
    
        if (!down_arrow_event)
            ErrorExit(TEXT("CreateEvent 2"));
    
    
        right_arrow_event = CreateEvent( NULL, TRUE, FALSE, TEXT("RightArrowEvent") );
    
    
        if (!right_arrow_event)
            ErrorExit(TEXT("CreateEvent 3"));
    
    
        left_arrow_event = CreateEvent( NULL, TRUE, FALSE, TEXT("LeftArrowEvent") );
    
    
        if (!left_arrow_event)
            ErrorExit(TEXT("CreateEvent 4"));
    
    
        escape_event = CreateEvent( NULL, TRUE, FALSE, TEXT("EscapeEvent") );
    
    
        if (!escape_event)
            ErrorExit(TEXT("CreateEvent 5"));
    
    
        clear_screen_event = CreateEvent( NULL, TRUE, FALSE, TEXT("ClearScrenEvent") );
    
    
        if(!clear_screen_event)
            ErrorExit(TEXT("CreateEvent 6"));
    
    
        debounce_event = CreateEvent( NULL, TRUE, FALSE, TEXT("DebounceEvent") );
    
    
        if(!debounce_event)
            ErrorExit(TEXT("CreateEvent 7"));
    
    
        return;
    }
    
    
    inline shared_game_data * create_shared_game_data_node( shared_game_data * data )
    {
        data = malloc(sizeof(shared_game_data));
    
    
        if (!data)
        {
            perror("Malloc");
            ExitProcess(1);
        }
    
    
        return data;
    
    
    }
    
    
    inline void create_threads( void * data, unsigned * thread_id )
    {
        unsigned index;
    
    
        DWORD msleep = 50;
        DWORD deb_msleep = 50;
        void * sleep = &msleep;
        void * deb_sleep = &deb_msleep;
    
    
        h_threads[0] = (HANDLE)_beginthreadex(NULL, 0, &event_loop, sleep, 0, &thread_id[0] );
        h_threads[1] = (HANDLE)_beginthreadex(NULL, 0, &left_arrow_handler, data, 0, &thread_id[1] );
        h_threads[2] = (HANDLE)_beginthreadex(NULL, 0, &right_arrow_handler, data, 0, &thread_id[2] );
        h_threads[3] = (HANDLE)_beginthreadex(NULL, 0, &up_arrow_handler, data, 0, &thread_id[3] );
        h_threads[4] = (HANDLE)_beginthreadex(NULL, 0, &down_arrow_handler, data, 0, &thread_id[4] );
        h_threads[5] = (HANDLE)_beginthreadex(NULL, 0, &clear_screen_handler, data, 0, &thread_id[5] );
        h_threads[6] = (HANDLE)_beginthreadex(NULL, 0, &debounce_events, deb_sleep, 0, &thread_id[6] );
    
    
        for ( index = 0; index < MAX_THREADS; index++ )
            if (!h_threads[index])
                ErrorExit("_beginthreadex");
    
    
        return;
    }
    
    
    void cleanup( )
    {
        close_threads();
        DeleteCriticalSection(&critical_section);
        close_events();
        free(data);
    
    
        return;
    }
    
    
    int main( int argc, char * argv[] )
    {
        if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
            SDL_errorexit( "SDL_Init", "SDL" );
    
    
        if (atexit(SDL_Quit))
        {
            perror("atexit");
            exit(1);
        }
    
    
        if (atexit(cleanup))
        {
            perror("Atexit");
            ExitProcess(1);
        }
    
    
        unsigned thread_id[MAX_THREADS] = {0};
    
    
        if (!InitializeCriticalSectionAndSpinCount(&critical_section, 0x0000050))
            ErrorExit(TEXT("InitialCriticalSectionAndSpinCount"));
    
    
        init_events();
    
    
        shared_game_data * game_data = NULL;
        game_data = create_shared_game_data_node(game_data);
    
    
        if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    
    
        atexit(SDL_Quit);
    
    
        game_data->screen = SDL_SetVideoMode( 640, 480, 16, SDL_HWSURFACE | SDL_DOUBLEBUF );
    
    
        if ( !game_data->screen )
            SDL_errorexit("SDL_SetVideoMode", "SDL");
    
    
        game_data->bmp = SDL_LoadBMP("sprite.bmp");
    
    
        if (!game_data->bmp)
            SDL_errorexit("SDL_LoadBMP", "SDL");
    
    
        SDL_SetColorKey( game_data->bmp, SDL_SRCCOLORKEY, SDL_MapRGB(game_data->bmp->format, 255, 0, 255) );
    
    
        game_data->dstrect.x = (game_data->screen->w - game_data->bmp->w) / 2;
        game_data->dstrect.y = (game_data->screen->h - game_data->bmp->h) / 2;
    
    
        SDL_FillRect(game_data->screen, 0, SDL_MapRGB(game_data->screen->format, 0, 0, 0));
        SDL_BlitSurface(game_data->bmp, 0, game_data->screen, &game_data->dstrect);
        SDL_Flip(game_data->screen);
    
    
        data = game_data;
        create_threads( data, thread_id );
        WaitForMultipleObjects(MAX_THREADS, h_threads, TRUE, INFINITE);
        SDL_FreeSurface(game_data->bmp);
    
    
        return 0;
    }
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  2. #2
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288
    Program crash[C/SDL/Win32]-cb-png

    Here is sprite.bmp, I forgot to include it earlier.
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  3. #3
    Registered User ledow's Avatar
    Join Date
    Dec 2011
    Posts
    435
    1) Your sprite is a PNG, not a BMP.
    2) Throw some printf()'s in there if your debugger can't load it. Then at least you have an idea what parts it gets past successfully (note: Use '\n' on the end of the string, and don't expect it to flush the string out to stdout before it crashes).
    3) With one printf, I eliminated almost the entirety of the main function down to "create_threads" from being the lines that crash (that doesn't mean they aren't the problem, just that they don't crash).
    4) With one printf per function, you could at least tell what functions are called, in what order, and whether they exit or not.
    5) I get an SDL screen pop up, so I know how far you can get with one run of the software. It just doesn't draw anything on it at all.

    I don't have a Windows debugger (I cross-compile with MinGW), so I can't help you further and I'm not going to read every line of your code to do so if you can't figure out that narrowing it down doesn't require a debugger, or even anything spectacularly technical to at least point the finger at a particular function / line.

    Narrow down your problem, and I'll help you. At the moment you're saying "My computer doesn't work" and expecting me to take it apart for you and find the cause.

    - Compiler warnings are like "Bridge Out Ahead" warnings. DON'T just ignore them.
    - A compiler error is something SO stupid that the compiler genuinely can't carry on with its job. A compiler warning is the compiler saying "Well, that's bloody stupid but if you WANT to ignore me..." and carrying on.
    - The best debugging tool in the world is a bunch of printf()'s for everything important around the bits you think might be wrong.

  4. #4
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288
    Quote Originally Posted by ledow View Post
    1) Your sprite is a PNG, not a BMP.
    2) Throw some printf()'s in there if your debugger can't load it. Then at least you have an idea what parts it gets past successfully (note: Use '\n' on the end of the string, and don't expect it to flush the string out to stdout before it crashes).
    3) With one printf, I eliminated almost the entirety of the main function down to "create_threads" from being the lines that crash (that doesn't mean they aren't the problem, just that they don't crash).
    4) With one printf per function, you could at least tell what functions are called, in what order, and whether they exit or not.
    5) I get an SDL screen pop up, so I know how far you can get with one run of the software. It just doesn't draw anything on it at all.

    I don't have a Windows debugger (I cross-compile with MinGW), so I can't help you further and I'm not going to read every line of your code to do so if you can't figure out that narrowing it down doesn't require a debugger, or even anything spectacularly technical to at least point the finger at a particular function / line.

    Narrow down your problem, and I'll help you. At the moment you're saying "My computer doesn't work" and expecting me to take it apart for you and find the cause.
    I apologize for the lack of details in my original post. I will respond to your statements in a more lucid manner.

    1) Yes, I didn't specify that the original image was a Windows Bitmap file, and I only posted it like that because the website told me I could not upload a .bmp file. If needed, I can try to attach the original file.
    2) I tried printf()'s first, but as you said, it didn't even go to the output buffer before the crash. Instead, I used stderr, since I knew that I would be a bit different buffering wise. When I used stderr, I got output. I'll explain more below about what steps I took before and after the original post in attempts to debug.
    3) I realized that too, but I neglected to add a lot of details.
    4) I didn't do that yet because I was, well honestly, being lazy, I will show the results of that improvement below.
    5) I got the SDL window to pop up, and it draws the image with the background transparent on my system.

    Here is a lucid explanation of what I did now to narrow it down for both you and I, and what I did before I posted.

    Beforehand :

    I took the MessageBox() function from the Windows API and attempted to use it as a debugging tool. Not the best choice, I know, but I'm lazy when it comes to debugging occasionally. I narrowed it down to it crashing sometime after create_threads() returned to main(). Then I posted here and ended up leaving out that piece of information.

    Afterwords :

    I made a bunch of fprintf()'s to tell me what was happening when the threads were created. I found that, obviously, since there is no FIFO with the function I used to create threads, it changed order. I noticed that some of my coordinates and events were a bit off, so I changed them to be handled properly. I then ran 3 trials and stored the results SDL put in a file temporarily in an untitled notepad program. I found that there is a sort of undefined behavior in my program. It crashes right away with some call orders, but it doesn't crash right away with some call orders. I also found that in the one trial that it didn't crash, I could move the image and all the events were being handled properly, but if I clicked off the program it would crash. I ran a debugger to see if some sort of segmentation fault was the cause of this behavior, but the debugger picked up nothing. Not even a SIGTRAP this time. I concluded that there was some problem in the way I created threads, but being unfamiliar with both win32 and SDL, I am still stumped. Here is the output I was getting from my three trials.

    First trial : Events are handled, image moves, but program crashes when I don't have the window active.

    Code:
    event_loop iteration : 0
    create_threads returned to main
    left_arrow_event initialized
    right_arrow_event initialized
    up_arrow_event initialized
    down_arrow_event initialized
    clear_screen_event initialized
    event_loop iteration : 1
    event_loop iteration : 2
    event_loop iteration : 3
    event_loop iteration : 4
    event_loop iteration : 5
    event_loop iteration : 6
    event_loop iteration : 7
    event_loop iteration : 8
    event_loop iteration : 9
    event_loop iteration : 10
    event_loop iteration : 11
    event_loop iteration : 12
    event_loop iteration : 13
    event_loop iteration : 14
    event_loop iteration : 15
    event_loop iteration : 16
    event_loop iteration : 17
    event_loop iteration : 18
    event_loop iteration : 19
    event_loop iteration : 20
    event_loop iteration : 21
    event_loop iteration : 22
    event_loop iteration : 23
    event_loop iteration : 24
    event_loop iteration : 25
    event_loop iteration : 26
    event_loop iteration : 27
    event_loop iteration : 28
    event_loop iteration : 29
    event_loop iteration : 30
    event_loop iteration : 31
    event_loop iteration : 32
    event_loop iteration : 33
    event_loop iteration : 34
    event_loop iteration : 35
    event_loop iteration : 36
    event_loop iteration : 37
    event_loop iteration : 38
    event_loop iteration : 39
    event_loop iteration : 40
    event_loop iteration : 41
    event_loop iteration : 42
    event_loop iteration : 43
    event_loop iteration : 44
    event_loop iteration : 45
    event_loop iteration : 46
    event_loop iteration : 47
    event_loop iteration : 48
    event_loop iteration : 49
    event_loop iteration : 50
    event_loop iteration : 51
    event_loop iteration : 52
    event_loop iteration : 53
    event_loop iteration : 54
    up_arrow_event initialized
    event_loop iteration : 55
    up_arrow_event initialized
    event_loop iteration : 56
    up_arrow_event initialized
    event_loop iteration : 57
    right_arrow_event initialized
    up_arrow_event initialized
    event_loop iteration : 58
    right_arrow_event initialized
    up_arrow_event initialized
    event_loop iteration : 59
    up_arrow_event initialized
    right_arrow_event initialized
    event_loop iteration : 60
    right_arrow_event initialized
    up_arrow_event initialized
    event_loop iteration : 61
    right_arrow_event initialized
    event_loop iteration : 62
    right_arrow_event initialized
    event_loop iteration : 63
    right_arrow_event initialized
    event_loop iteration : 64
    right_arrow_event initialized
    event_loop iteration : 65
    right_arrow_event initialized
    event_loop iteration : 66
    right_arrow_event initialized
    event_loop iteration : 67
    right_arrow_event initialized
    event_loop iteration : 68
    right_arrow_event initialized
    event_loop iteration : 69
    event_loop iteration : 70
    event_loop iteration : 71
    event_loop iteration : 72
    event_loop iteration : 73
    event_loop iteration : 74
    down_arrow_event initialized
    event_loop iteration : 75
    down_arrow_event initialized
    event_loop iteration : 76
    down_arrow_event initialized
    event_loop iteration : 77
    down_arrow_event initialized
    event_loop iteration : 78
    down_arrow_event initialized
    event_loop iteration : 79
    down_arrow_event initialized
    event_loop iteration : 80
    down_arrow_event initialized
    event_loop iteration : 81
    down_arrow_event initialized
    event_loop iteration : 82
    down_arrow_event initialized
    event_loop iteration : 83
    down_arrow_event initialized
    event_loop iteration : 84
    down_arrow_event initialized
    Second trial : Program crashes immediately

    Code:
    create_threads returned to main
    left_arrow_event initialized
    up_arrow_event initialized
    clear_screen_event initialized
    event_loop iteration : 0
    right_arrow_event initialized
    down_arrow_event initialized
    Third trial : Same result as second.

    Code:
    left_arrow_event initialized
    create_threads returned to main
    event_loop iteration : 0
    up_arrow_event initialized
    clear_screen_event initialized
    right_arrow_event initialized
    down_arrow_event initialized
    Code with minor bugs fixed and fprintf()'s added :

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    #include <process.h>
    #define WIN_32_LEAN_AND_MEAN
    #include <windows.h>
    #include <strsafe.h>
    
    
    #include <SDL/SDL.h>
    
    
    #define MAX_RIGHT 79
    #define MAX_DOWN 24
    
    
    #define MAX_THREADS 7
    
    
    /* Key-input macro and usage credit goes to : http://cboard.cprogramming.com/c-programming/157472-c-pong-program-need-help-smoothing-animations.html */
    
    
    #define VKEY_IS_PRESSED(vk)    ( GetAsyncKeyState(vk) & 0x8000 )
    
    
    enum v_key
    {
        up_arrow = VK_UP,
        down_arrow = VK_DOWN,
        right_arrow = VK_RIGHT,
        left_arrow = VK_LEFT,
        clearscreen = VK_BACK,
        escape = VK_ESCAPE
    };
    
    
    typedef struct shared_game_data
    {
        SDL_Surface * screen;
        SDL_Surface * bmp;
        SDL_Rect dstrect;
    
    
    
    
    } shared_game_data;
    
    
    void * data = NULL;
    HANDLE h_threads[MAX_THREADS] = {0};
    
    
    HANDLE up_arrow_event = 0;
    HANDLE down_arrow_event = 0;
    HANDLE right_arrow_event = 0;
    HANDLE left_arrow_event = 0;
    HANDLE clear_screen_event = 0;
    HANDLE escape_event = 0;
    HANDLE debounce_event = 0;
    
    
    CRITICAL_SECTION critical_section;
    
    
    BOOL is_debounce = FALSE;
    
    
    /* Credit to the board : http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1044844545&id=1043284392 */
    
    
    void gotoxy(int x, int y)
    {
      COORD coord;
      coord.X = x;
      coord.Y = y;
      SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
    }
    
    
    /* Credit to Microsoft : http://msdn.microsoft.com/en-us/library/windows/desktop/ms682022(v=vs.85).aspx */
    
    
    void cls( HANDLE hConsole )
    {
       COORD coordScreen = { 0, 0 };
       DWORD cCharsWritten;
       CONSOLE_SCREEN_BUFFER_INFO csbi;
       DWORD dwConSize;
    
    
       if( !GetConsoleScreenBufferInfo( hConsole, &csbi ))
          return;
    
    
       dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
    
    
       if( !FillConsoleOutputCharacter( hConsole, (TCHAR) ' ', dwConSize,coordScreen, &cCharsWritten ))
          return;
    
    
       if( !GetConsoleScreenBufferInfo( hConsole, &csbi ))
          return;
    
    
       if( !FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten ))
          return;
    
    
       SetConsoleCursorPosition( hConsole, coordScreen );
    }
    
    
    /* Credit to Microsoft : http://msdn.microsoft.com/en-us/library/windows/apps/ms680582(v=vs.85).aspx */
    
    
    void ErrorExit(LPTSTR lpszFunction)
    {
        LPVOID lp_msg_buf;
        LPVOID lp_display_buf;
        DWORD dw = GetLastError();
    
    
        FormatMessage
        (
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lp_msg_buf,
        0,
        NULL
        );
    
    
        lp_display_buf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lp_msg_buf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
    
    
        StringCchPrintf((LPTSTR)lp_display_buf, LocalSize(lp_display_buf) / sizeof(TCHAR), TEXT("%s failed with error %d: %s"), lpszFunction, dw, lp_msg_buf);
        MessageBox(NULL, (LPCTSTR)lp_display_buf, TEXT("Error"), MB_OK);
    
    
        LocalFree(lp_msg_buf);
        LocalFree(lp_display_buf);
        ExitProcess(dw);
    }
    
    
    void SDL_errorexit( const char * error_message, const char * caption  )
    {
            char buffer[BUFSIZ];
            StringCbPrintfA(buffer, BUFSIZ, "%s : %s", error_message, SDL_GetError());
            MessageBox( NULL, buffer, caption, MB_OK | MB_ICONEXCLAMATION );
    
    
            exit(1);
    }
    
    
    void close_events( )
    {
        CloseHandle(up_arrow_event);
        CloseHandle(down_arrow_event);
        CloseHandle(right_arrow_event);
        CloseHandle(left_arrow_event);
        CloseHandle(escape_event);
        CloseHandle(clear_screen_event);
        CloseHandle(debounce_event);
    
    
        return;
    }
    
    
    void close_threads( )
    {
        unsigned index;
    
    
        for (index = 0; index < MAX_THREADS; index++)
            CloseHandle(h_threads[index]);
    
    
        return;
    }
    
    
    unsigned __stdcall debounce_events( void * m_sleep )
    {
        const DWORD msleep = *(DWORD *)m_sleep;
        DWORD return_value = 0;
        HANDLE objects[2] = {debounce_event, escape_event};
    
    
        for ( ; ; )
        {
    
    
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
    
    
                    is_debounce = TRUE;
                    Sleep(msleep);
                    is_debounce = FALSE;
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    unsigned __stdcall event_loop( void * m_sleep )
    {
        const DWORD msleep = *(DWORD *)m_sleep;
        unsigned iteration = 0;
    
    
        for ( ; ; )
        {
            fprintf(stderr,"event_loop iteration : %d\n", iteration++);
    
    
            if (!is_debounce)
            {
                if ( VKEY_IS_PRESSED(escape) )
                {
                    if ( !SetEvent(escape_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-Escape"));
                    }
    
    
                    return 0;
                }
    
    
                if ( VKEY_IS_PRESSED(up_arrow) )
                {
                    if ( !SetEvent(up_arrow_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-UpArrow"));
                    }
    
    
                    if ( !SetEvent(debounce_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("DebounceEvent-UpArrow"));
                    }
                }
    
    
                if ( VKEY_IS_PRESSED(down_arrow) )
                {
                    if ( !SetEvent(down_arrow_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-DownArrow"));
                    }
    
    
                    if ( !SetEvent(debounce_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("DebounceEvent-UpArrow"));
                    }
                }
    
    
                if ( VKEY_IS_PRESSED(right_arrow) )
                {
    
    
                    if ( !SetEvent(right_arrow_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-RightArrow"));
                    }
    
    
                    if ( !SetEvent(debounce_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("DebounceEvent-UpArrow"));
                    }
                }
    
    
                if ( VKEY_IS_PRESSED(left_arrow) )
                {
                    if ( !SetEvent(left_arrow_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-LeftArrow"));
                    }
    
    
                    if ( !SetEvent(debounce_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("DebounceEvent-UpArrow"));
                    }
                }
    
    
                if ( VKEY_IS_PRESSED(clearscreen) )
                {
                    if ( !SetEvent(clear_screen_event) )
                    {
                        close_events();
                        ErrorExit(TEXT("SetEvent-ClearScreen"));
                    }
                }
    
    
            }
    
    
            Sleep(msleep);
        }
    
    
        return 1;
    }
    
    
    unsigned __stdcall left_arrow_handler( void * parameter )
    {
        DWORD return_value = 0;
        HANDLE objects[2] = {left_arrow_event, escape_event};
        shared_game_data * my_data = (shared_game_data *)parameter;
    
    
        for ( ; ; )
        {
            fprintf(stderr, "left_arrow_event initialized\n");
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
                    EnterCriticalSection(&critical_section);
    
    
                    if ( (my_data->dstrect.x - 1) > -1 )
                    {
                        SDL_FillRect(my_data->screen, NULL, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        --my_data->dstrect.x;
                        SDL_FillRect(my_data->screen, 0, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        SDL_BlitSurface(my_data->bmp, 0, my_data->screen, &my_data->dstrect);
                        SDL_Flip(my_data->screen);
                    }
    
    
                    LeaveCriticalSection(&critical_section);
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    unsigned __stdcall right_arrow_handler( void * parameter )
    {
        DWORD return_value = 0;
        HANDLE objects[2] = {right_arrow_event, escape_event};
        shared_game_data * my_data = (shared_game_data *)parameter;
    
    
        for ( ; ; )
        {
            fprintf(stderr, "right_arrow_event initialized\n");
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
                    EnterCriticalSection(&critical_section);
    
    
                    if ( (my_data->dstrect.x + 1) > -1 )
                    {
                        SDL_FillRect(my_data->screen, NULL, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        ++my_data->dstrect.x;
                        SDL_FillRect(my_data->screen, 0, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        SDL_BlitSurface(my_data->bmp, 0, my_data->screen, &my_data->dstrect);
                        SDL_Flip(my_data->screen);
                    }
    
    
                    LeaveCriticalSection(&critical_section);
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    unsigned __stdcall down_arrow_handler( void * parameter )
    {
        DWORD return_value = 0;
        HANDLE objects[2] = {down_arrow_event, escape_event};
        shared_game_data * my_data = (shared_game_data *)parameter;
    
    
        for ( ; ; )
        {
            fprintf(stderr, "down_arrow_event initialized\n");
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
                    EnterCriticalSection(&critical_section);
    
    
                    if ( (my_data->dstrect.y + 1) > -1 )
                    {
                        SDL_FillRect(my_data->screen, NULL, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        ++my_data->dstrect.y;
                        SDL_FillRect(my_data->screen, 0, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        SDL_BlitSurface(my_data->bmp, 0, my_data->screen, &my_data->dstrect);
                        SDL_Flip(my_data->screen);
                    }
    
    
                    LeaveCriticalSection(&critical_section);
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    unsigned __stdcall up_arrow_handler( void * parameter )
    {
        DWORD return_value = 0;
        HANDLE objects[2] = {up_arrow_event, escape_event};
        shared_game_data * my_data = (shared_game_data *)parameter;
    
    
        for ( ; ; )
        {
            fprintf(stderr, "up_arrow_event initialized\n");
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
                    EnterCriticalSection(&critical_section);
    
    
                    if ( (my_data->dstrect.y - 1) > -1 )
                    {
                        SDL_FillRect(my_data->screen, NULL, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        --my_data->dstrect.y;
                        SDL_FillRect(my_data->screen, 0, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                        SDL_BlitSurface(my_data->bmp, 0, my_data->screen, &my_data->dstrect);
                        SDL_Flip(my_data->screen);
                    }
    
    
                    LeaveCriticalSection(&critical_section);
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    unsigned __stdcall clear_screen_handler( void * parameter )
    {
        DWORD return_value = 0;
        HANDLE objects[2] = {clear_screen_event, escape_event};
        shared_game_data * my_data = (shared_game_data *)parameter;
    
    
        for ( ; ; )
        {
            fprintf(stderr, "clear_screen_event initialized\n");
    
    
            return_value = WaitForMultipleObjects(2, objects, FALSE, INFINITE);
    
    
            switch ( return_value )
            {
                case WAIT_OBJECT_0 :
                    EnterCriticalSection(&critical_section);
    
    
                    SDL_FillRect(my_data->screen, NULL, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                    my_data->dstrect.x = 0;
                    my_data->dstrect.y = 0;
                    SDL_FillRect(my_data->screen, 0, SDL_MapRGB(my_data->screen->format, 0, 0, 0));
                    SDL_BlitSurface(my_data->bmp, 0, my_data->screen, &my_data->dstrect);
                    SDL_Flip(my_data->screen);
    
    
                    LeaveCriticalSection(&critical_section);
    
    
                    ResetEvent(objects[0]);
    
    
                    break;
                case WAIT_OBJECT_0 + 1 :
                    return 0;
            }
        }
    
    
        return 0;
    }
    
    
    void init_events ( )
    {
        /* Create our keyboard events */
    
    
        up_arrow_event = CreateEvent( NULL, TRUE, FALSE, TEXT("UpArrowEvent") );
    
    
        if (!up_arrow_event)
            ErrorExit(TEXT("CreateEvent 1"));
    
    
        down_arrow_event = CreateEvent( NULL, TRUE, FALSE, TEXT("DownArrowEvent") );
    
    
        if (!down_arrow_event)
            ErrorExit(TEXT("CreateEvent 2"));
    
    
        right_arrow_event = CreateEvent( NULL, TRUE, FALSE, TEXT("RightArrowEvent") );
    
    
        if (!right_arrow_event)
            ErrorExit(TEXT("CreateEvent 3"));
    
    
        left_arrow_event = CreateEvent( NULL, TRUE, FALSE, TEXT("LeftArrowEvent") );
    
    
        if (!left_arrow_event)
            ErrorExit(TEXT("CreateEvent 4"));
    
    
        escape_event = CreateEvent( NULL, TRUE, FALSE, TEXT("EscapeEvent") );
    
    
        if (!escape_event)
            ErrorExit(TEXT("CreateEvent 5"));
    
    
        clear_screen_event = CreateEvent( NULL, TRUE, FALSE, TEXT("ClearScrenEvent") );
    
    
        if(!clear_screen_event)
            ErrorExit(TEXT("CreateEvent 6"));
    
    
        debounce_event = CreateEvent( NULL, TRUE, FALSE, TEXT("DebounceEvent") );
    
    
        if(!debounce_event)
            ErrorExit(TEXT("CreateEvent 7"));
    
    
        return;
    }
    
    
    inline shared_game_data * create_shared_game_data_node( shared_game_data * data )
    {
        data = malloc(sizeof(shared_game_data));
    
    
        if (!data)
        {
            perror("Malloc");
            ExitProcess(1);
        }
    
    
        return data;
    
    
    }
    
    
    inline void create_threads( void * data, unsigned * thread_id )
    {
        unsigned index;
    
    
        DWORD msleep = 50;
        DWORD deb_msleep = 50;
        void * sleep = &msleep;
        void * deb_sleep = &deb_msleep;
    
    
        h_threads[0] = (HANDLE)_beginthreadex(NULL, 0, &event_loop, sleep, 0, &thread_id[0] );
        h_threads[1] = (HANDLE)_beginthreadex(NULL, 0, &left_arrow_handler, data, 0, &thread_id[1] );
        h_threads[2] = (HANDLE)_beginthreadex(NULL, 0, &right_arrow_handler, data, 0, &thread_id[2] );
        h_threads[3] = (HANDLE)_beginthreadex(NULL, 0, &up_arrow_handler, data, 0, &thread_id[3] );
        h_threads[4] = (HANDLE)_beginthreadex(NULL, 0, &down_arrow_handler, data, 0, &thread_id[4] );
        h_threads[5] = (HANDLE)_beginthreadex(NULL, 0, &clear_screen_handler, data, 0, &thread_id[5] );
        h_threads[6] = (HANDLE)_beginthreadex(NULL, 0, &debounce_events, deb_sleep, 0, &thread_id[6] );
    
    
        for ( index = 0; index < MAX_THREADS; index++ )
            if (!h_threads[index])
                ErrorExit("_beginthreadex");
    
    
        return;
    }
    
    
    void cleanup( )
    {
        close_threads();
        DeleteCriticalSection(&critical_section);
        close_events();
        free(data);
    
    
        return;
    }
    
    
    int main( int argc, char * argv[] )
    {
        if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
            SDL_errorexit( "SDL_Init", "SDL" );
    
    
        if (atexit(SDL_Quit))
        {
            perror("atexit");
            exit(1);
        }
    
    
        if (atexit(cleanup))
        {
            perror("Atexit");
            ExitProcess(1);
        }
    
    
        unsigned thread_id[MAX_THREADS] = {0};
    
    
        if (!InitializeCriticalSectionAndSpinCount(&critical_section, 0x0000050))
            ErrorExit(TEXT("InitialCriticalSectionAndSpinCount"));
    
    
        init_events();
    
    
        shared_game_data * game_data = NULL;
        game_data = create_shared_game_data_node(game_data);
    
    
        if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    
    
        atexit(SDL_Quit);
    
    
        game_data->screen = SDL_SetVideoMode( 640, 480, 16, SDL_HWSURFACE | SDL_DOUBLEBUF );
    
    
        if ( !game_data->screen )
            SDL_errorexit("SDL_SetVideoMode", "SDL");
    
    
        game_data->bmp = SDL_LoadBMP("sprite.bmp");
    
    
        if (!game_data->bmp)
            SDL_errorexit("SDL_LoadBMP", "SDL");
    
    
        SDL_SetColorKey( game_data->bmp, SDL_SRCCOLORKEY, SDL_MapRGB(game_data->bmp->format, 255, 0, 255) );
    
    
        game_data->dstrect.x = (game_data->screen->w - game_data->bmp->w) / 2;
        game_data->dstrect.y = (game_data->screen->h - game_data->bmp->h) / 2;
    
    
        SDL_FillRect(game_data->screen, 0, SDL_MapRGB(game_data->screen->format, 0, 0, 0));
        SDL_BlitSurface(game_data->bmp, 0, game_data->screen, &game_data->dstrect);
        SDL_Flip(game_data->screen);
    
    
        data = game_data;
        create_threads( data, thread_id );
        fprintf(stderr, "create_threads returned to main\n");
        WaitForMultipleObjects(MAX_THREADS, h_threads, TRUE, INFINITE);
        SDL_FreeSurface(game_data->bmp);
    
    
        return 0;
    }

    Concluding Statements : I'm sure why my program crashes would be fairly obvious to someone. With my lack of experience, I am stumped. I hope that is enough information for you Ledow.
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  5. #5
    Registered User ledow's Avatar
    Join Date
    Dec 2011
    Posts
    435
    Sigh. Well, it's still an unintelligible mass of information that isn't particularly relevant. However, I will abandon that track and now wonder why you're even doing what you're doing. I've just managed to actually bother to copy your code into an IDE and start looking at it for you because I saw you struggling and thought I could at least give you a pointer.

    Why on earth do you have separate threads for handling each key event? Why on earth do you have several functions that are the subject of those threads that are all, basically, identical? Why are you trying to perform graphics calls from inside those threads at all (ignoring the fact that you've tried to put locking around it, "http://wiki.libsdl.org/FAQDevelopment#Can_I_call_SDL_video_functions_from _multiple_threads" basically says "don't do it"). Your main thread (i.e. the one which calls create_threads, not anything you've created) is the ONLY SDL command that should ever try to draw to the screen. If you must have separate threads for everything (which is kind of pointless and only going to make the program EVEN MORE unpredictable when you press a key that those threads are listening out for), then they can only tell the main thread what to draw in a thread-safe way (i.e. put things into shared memory that the main thread acts upon).

    This is really a horrendous piece of code. Can I ask why you're doing what you're doing rather than an event loop? Quite what kind of difference / performance gain / simplicity of code are you trying to achieve? And why not use the SDL thread functions which hide all this Windows-only junk from you and do it in a slightly more SDL-safe way (but still don't let you draw to SDL from anything but the initial program thread)? All I see is a threaded mess where lots of virtually identical threads are all doing too much work, all trying to lock the same critical sections and probably deadlocking doing so, and drawing to surfaces in a way that SDL has never been able to cope with.

    Your attempts at debugging started off reasonable but have now descended into farce. Debugging a threaded app is more difficult and, yes, sometimes debuggers throw their toys out of their pram, especially with threads. So you could literally THROW debugging statements at it if you need to know where it crashed - the actual function it stops in is only the first step and if it's not as consistent as you'd like, then you need to find out why. I'd have messages thrown like mad around the locking so I know who "owned" the critical section at any one time. Chances are those critical section locks are working (and what's the point of such threading if no two threads can actually do the thing they need to at the same time - they basically all sit waiting for an event to arrive from yet-another-thread?) but that the SDL drawing / event commands are just causing havoc as they tamper with surfaces and the screen outside of the SDL main thread that is desperately trying to draw them while they change under its feet.

    Your whole app, I could replicate with a single loop and no threads whatsoever and - even under ideal conditions - outperform yours. Hell, I have a project from several years ago that uses Fast Events in SDL (which is a simple demonstration of threaded SDL events that I believe is pretty moot with new SDL code nowadays) to the same effect, and they don't go anywhere near as far as having two threads, let alone the amount you have.

    You need to sit down and think of what you're trying to achieve and why it needs so many threads. You desperately need to read the SDL FAQ's and threading API. And you need to learn what a thread is for. It's for a simultaneous action that can occur when other independent actions are happening. Pretty much, your threads spend their entire lives waiting for messages from another thread, and then fighting over whose turn it is to actually run. And that "controller" thread is spawned from main, who just sits there waiting for it to terminate. Is that really a suitable use of an modern quad-core machine capable of running dozens of threads simultaneously?

    It's like hiring a bunch of builders who sit around all day waiting for the foreman to come up and say "cut that skirting board" - they cut it, it takes two seconds, then they sit around and wait for the rest of the day until he comes back and says "sand that skirting board" and then wait for him to come back and say "fit that skirting board" and then wait for him to come back and say "paint that skirting board". And they only have one tool between the lot of them and have to wait for each other to finish using it before they can start on their job. Compare to situation with no foreman, just a single builder, who is told to "cut that skirting board, then sand, fit and paint it" (i.e. single thread, execution in order, and a nice event loop).

    This is a good demonstration of over-thinking and over-engineering a problem, to drastic effect. And even if everything worked exactly as you intend it to, you'll see no benefit from it whatsoever - just undebuggable, unreadable, slower code.

    - Compiler warnings are like "Bridge Out Ahead" warnings. DON'T just ignore them.
    - A compiler error is something SO stupid that the compiler genuinely can't carry on with its job. A compiler warning is the compiler saying "Well, that's bloody stupid but if you WANT to ignore me..." and carrying on.
    - The best debugging tool in the world is a bunch of printf()'s for everything important around the bits you think might be wrong.

  6. #6
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288
    I rethought it as you suggested and came up with this code completely written in the SDL API.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    
    #include <SDL/SDL.h>
    
    
    void SDL_errorexit( const char * error_message )
    {
        char buffer[BUFSIZ];
        sprintf(buffer, "%s : %s", error_message, SDL_GetError());
        fprintf(stderr, "%s", buffer);
    
    
        exit(1);
    }
    
    
    int main( int argc, char * argv[] )
    {
        SDL_Event event;
        SDL_Surface * screen;
        SDL_Surface * bmp;
        SDL_Rect dstrect;
        SDL_Rect xy_dstrect;
    
    
        xy_dstrect.x = 0;
        xy_dstrect.y = 0;
    
    
        if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
            SDL_errorexit( "SDL_Init");
    
    
        if (atexit(SDL_Quit))
        {
            perror("atfexit");
            exit(1);
        }
    
    
        screen = SDL_SetVideoMode( 640, 480, 16, SDL_HWSURFACE | SDL_DOUBLEBUF );
    
    
        if ( !screen )
            SDL_errorexit("SDL_SetVideoMode");
    
    
        bmp = SDL_LoadBMP("sprite.bmp");
    
    
        if (!bmp)
            SDL_errorexit("SDL_LoadBMP");
    
    
        SDL_SetColorKey( bmp, SDL_SRCCOLORKEY, SDL_MapRGB(bmp->format, 255, 0, 255) );
    
    
        dstrect.x = (screen->w - bmp->w) / 2;
        dstrect.y = (screen->h - bmp->h) / 2;
    
    
        SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
        SDL_BlitSurface(bmp, 0, screen, &dstrect);
        SDL_Flip(screen);
    
    
        for ( ; ; )
        {
            /* While-loop was from SDL documentation : http://www.libsdl.org/release/SDL-1.2.15/docs/html/guideinputkeyboard.html */
    
    
            while( SDL_PollEvent( &event ) )
            {
                switch( event.type )
                {
                    case SDL_QUIT :
                        goto endloop;
                    /* Keydown event */
                    case SDL_KEYDOWN :
                        switch( event.key.keysym.sym )
                        {
                            case SDLK_LEFT :
                                xy_dstrect.x = -1;
                            break;
    
    
                            case SDLK_RIGHT :
                                xy_dstrect.x = 1;
                            break;
    
    
                            case SDLK_UP :
                                xy_dstrect.y = -1;
                            break;
    
    
                            case SDLK_DOWN :
                                xy_dstrect.y = 1;
                            break;
    
    
                            case SDLK_ESCAPE :
                                goto endloop;
    
    
                            default :
                            break;
                        }
    
    
                    break;
                    /* End keydown event */
    
    
                    /* Keyup event */
    
    
                    case SDL_KEYUP:
                        switch( event.key.keysym.sym )
                        {
                            case SDLK_LEFT:
                                if( xy_dstrect.x < 0 )
                                    xy_dstrect.x = 0;
                            break;
    
    
                            case SDLK_RIGHT:
                                if( xy_dstrect.x > 0 )
                                    xy_dstrect.x = 0;
                            break;
    
    
                            case SDLK_UP:
                                if( xy_dstrect.y < 0 )
                                    xy_dstrect.y = 0;
                            break;
    
    
                            case SDLK_DOWN:
                                if( xy_dstrect.y > 0 )
                                    xy_dstrect.y = 0;
                            break;
    
    
                            default:
                            break;
                    }
    
    
                    /* End keyup event */
    
    
                    break;
    
    
                    default:
                    break;
                }
            }
    
            dstrect.x += xy_dstrect.x;
            dstrect.y += xy_dstrect.y;
    
    
            SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
            SDL_BlitSurface(bmp, 0, screen, &dstrect);
            SDL_Flip(screen);
        } endloop:
    
    
        SDL_FreeSurface(bmp);
    
    
        return 0;
    }
    I am having trouble figuring out how to limit the x and y coordinates to the screen size when I move the picture right and down though.
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  7. #7
    Registered User ledow's Avatar
    Join Date
    Dec 2011
    Posts
    435
    Well, that's better. You can debug it. You can understand it. You stand half a chance of working out where the flow of the program is on a bit of paper. And as you'll notice as you code more, almost every SDL program follows a similar pattern for it's event loop.

    How to limit the coordinates? Think about what you want to limit. X and Y are the top-left corner of the image. You don't want them to go off the left of the screen so you never want them to be less than 0. You've worked that bit out.

    But on the right-hand side, it's not the top-left corner you need to worry about. It's the bottom-right corner. This is at coordinates "x + image width" and "y + image height". You don't want that coordinate to go higher than "screen width" or "screen height" respectively. In the same place that you have your tests to see if it goes less than 0 (and if it is, make it equal to 0) you want a similar test that if, say, x goes more than "x + image width", then you make it stay at "x + image width" instead. And similarly for y.

    I'm sure you can go from there to finding the line of code that works now.

    P.S. get rid of that goto crap and break out of the loop properly instead. It's okay for now, but it's a bad habit to just fly out of loops like that. All you need is a variable that tells you when to stop that is almost always 0, but when you actually want to quit it becomes something else instead (1? TRUE?). And then your while command can also check to see if it's time to break out or not.

    - Compiler warnings are like "Bridge Out Ahead" warnings. DON'T just ignore them.
    - A compiler error is something SO stupid that the compiler genuinely can't carry on with its job. A compiler warning is the compiler saying "Well, that's bloody stupid but if you WANT to ignore me..." and carrying on.
    - The best debugging tool in the world is a bunch of printf()'s for everything important around the bits you think might be wrong.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Program Crash
    By juice in forum C Programming
    Replies: 4
    Last Post: 11-18-2011, 11:17 PM
  2. Why does this program crash when I do this?
    By Witch in forum C Programming
    Replies: 4
    Last Post: 03-18-2010, 07:10 PM
  3. my program crash?
    By vrkiller in forum C++ Programming
    Replies: 10
    Last Post: 03-04-2009, 03:03 PM
  4. Why Does My Program Crash?
    By Grantyt3 in forum C++ Programming
    Replies: 20
    Last Post: 09-29-2005, 05:34 PM
  5. Why does the program crash?
    By SkyRaign in forum C++ Programming
    Replies: 8
    Last Post: 09-25-2005, 10:06 AM